library SpellBar requires /*
*/ UnitDex /*
*/ Practicals /*
*/ Constants /*
*/ Dto /*
*/ Unit /*
*/

    globals
        private constant integer BAR_DUMMY     = 'sbar' // the default one
        private constant player  BAR_OWNER     = Player(PLAYER_NEUTRAL_PASSIVE) // owner of the dummy
        private constant real    UPDATE_POSITION_PERIOD = 0.03 // the timer period used with .targetUnit
    endglobals

    /**
    *
    * 施法进度条
    *
    */
    struct SpellBar extends array
        
        boolean m_isReverse
        real xOffset
        real yOffset

        private unit m_owner
        private unit m_bar
        private integer m_count
        private timer m_timer

        method operator zOffset= takes real offset returns nothing
            call SetUnitFlyHeight(this.m_bar, offset, 0)
        endmethod
        
        method operator zOffset takes nothing returns real
            return GetUnitFlyHeight(this.m_bar)
        endmethod

        method destroy takes nothing returns nothing
            call ReleaseTimer(this.m_timer)
            call RemoveUnit(this.m_bar)
            set this.m_owner = null
            set this.m_timer = null
        endmethod

        static method get takes unit u returns thistype
            local thistype this = thistype(Unit.get(u))
            
            if this.m_owner != null then
                return this
            endif
            
            return 0
        endmethod

        static method create takes unit u returns thistype
            local thistype this = get(u)

            if this > 0 then
                call this.destroy()
            endif

            set this.m_owner = u
            set this.m_isReverse = false
            set this.m_count = 0
            set this.xOffset = 0
            set this.yOffset = 0
            
            return this
        endmethod

        private method getDataTimer takes integer data returns timer
            if this.m_timer == null then
                set this.m_timer = NewTimer()
                call SetTimerData(this.m_timer, data)
            endif
            return this.m_timer
        endmethod

        private static method anon__6 takes nothing returns nothing
            local thistype this = GetTimerData(GetExpiredTimer())
            
            if this.m_count > 0 then
                set this.m_count = this.m_count - 1
                call SetUnitX(this.m_bar, GetUnitX(this.m_owner) + this.xOffset)
                call SetUnitY(this.m_bar, GetUnitY(this.m_owner) + this.yOffset)
            else
                call IssueImmediateOrderById(this.m_owner, ORDER_NOTARG_STOP)
                call this.destroy()
            endif
        endmethod

        method start takes real duration, real offset returns nothing
            local real x = GetUnitX(this.m_owner)
            local real y = GetUnitY(this.m_owner)

            set UnitDex.Enabled = false
            set this.m_bar = CreateUnit(BAR_OWNER, BAR_DUMMY, x, y, 0.00)
            set UnitDex.Enabled = true

            set this.xOffset = 0
            set this.yOffset = offset
            set this.zOffset = 30
            
            if this.m_isReverse then
                call SetUnitAnimation(this.m_bar, "spell")
            else
                call SetUnitAnimation(this.m_bar, "attack")
            endif
            call SetUnitTimeScale(this.m_bar, 10.00 / duration)

            set this.m_count = R2I(duration / UPDATE_POSITION_PERIOD)
            call TimerStart(getDataTimer(this), UPDATE_POSITION_PERIOD, true, function thistype.anon__6)
        endmethod

    endstruct

endlibrary